use pest_derive::Parser;
use pest::Parser;
use std::env;
use std::fs;

#[derive(Parser)]
#[grammar = "grammar.pest"]
struct SysYParser;

fn find_illegal_chars(src: &str) -> Vec<usize> {
    let mut error_lines = Vec::new();
    let mut lines: Vec<&str> = src.lines().collect();
    
    // 添加最后一行（如果源文件不以换行符结尾）
    if !src.is_empty() && !src.ends_with('\n') {
        lines.push("");
    }
    
    for (line_idx, line) in lines.iter().enumerate() {
        let line_no = line_idx + 1;
        for ch in line.chars() {
            // 检查是否为非法字符
            if !ch.is_alphanumeric() && 
               !ch.is_whitespace() && 
               !['_', '+', '-', '*', '/', '%', '=', '!', '<', '>', '&', '|', 
                 '(', ')', '[', ']', '{', '}', ',', ';'].contains(&ch) {
                error_lines.push(line_no);
                break; // 每行只报告一次
            }
        }
    }
    
    error_lines
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        eprintln!("Usage: compiler <input.sy>");
        return;
    }
    let src = fs::read_to_string(&args[1]).expect("read file failed");

    // 首先检查是否有非法字符
    let illegal_char_lines = find_illegal_chars(&src);
    if !illegal_char_lines.is_empty() {
        for line_no in illegal_char_lines {
            eprintln!("Error type A at Line {}: Mysterious character.", line_no);
        }
        return;
    }

    // 如果没有非法字符，再进行正常解析
    match SysYParser::parse(Rule::file, &src) {
        Ok(pairs) => {
            // 收集并输出所有 token
            let mut tokens = Vec::new();
            
            let file_pair = pairs.into_iter().next().unwrap();
            for pair in file_pair.into_inner() {
                let rule = pair.as_rule();
                let text = pair.as_str();
                let (line, _) = pair.line_col();

                match rule {
                    Rule::INTEGER_CONST => {
                        let val = if text.starts_with("0x") || text.starts_with("0X") {
                            match i64::from_str_radix(&text[2..], 16) {
                                Ok(v) => v,
                                Err(_) => {
                                    eprintln!("Error type A at Line {}: Invalid hexadecimal constant", line);
                                    return;
                                }
                            }
                        } else if text.starts_with('0') && text.len() > 1 {
                            if text.chars().all(|c| c >= '0' && c <= '7') {
                                match i64::from_str_radix(&text[1..], 8) {
                                    Ok(v) => v,
                                    Err(_) => {
                                        eprintln!("Error type A at Line {}: Invalid octal constant", line);
                                        return;
                                    }
                                }
                            } else {
                                // 八进制包含非法数字（如8或9）
                                eprintln!("Error type A at Line {}: Invalid octal constant", line);
                                return;
                            }
                        } else {
                            match text.parse::<i64>() {
                                Ok(v) => v,
                                Err(_) => {
                                    eprintln!("Error type A at Line {}: Invalid integer constant", line);
                                    return;
                                }
                            }
                        };
                        tokens.push(format!("INTEGER_CONST {} at Line {}.", val, line));
                    }
                    Rule::CONST | Rule::INT | Rule::VOID | Rule::IF | Rule::ELSE | Rule::WHILE |
                    Rule::BREAK | Rule::CONTINUE | Rule::RETURN | Rule::IDENT |
                    Rule::PLUS | Rule::MINUS | Rule::MUL | Rule::DIV | Rule::MOD |
                    Rule::ASSIGN | Rule::EQ | Rule::NEQ | Rule::LT | Rule::LE |
                    Rule::GT | Rule::GE | Rule::NOT | Rule::AND | Rule::OR |
                    Rule::L_PAREN | Rule::R_PAREN | Rule::L_BRACKT | Rule::R_BRACKT |
                    Rule::L_BRACE | Rule::R_BRACE | Rule::COMMA | Rule::SEMICOLON => {
                        let rule_str = format!("{:?}", rule);
                        let name = rule_str.trim_start_matches("Rule::");
                        tokens.push(format!("{} {} at Line {}.", name, text, line));
                    }
                    _ => {} // 忽略隐藏规则
                }
            }
            
            // 输出所有 token
            for token in tokens {
                println!("{}", token);
            }
        }
        Err(e) => {
            let line = match e.line_col {
                pest::error::LineColLocation::Pos((l, _)) => l,
                pest::error::LineColLocation::Span((l, _), _) => l,
            };
            eprintln!("Error type A at Line {}: Mysterious character.", line);
        }
    }
}